home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-06-20 | 8.9 KB | 308 lines | [TEXT/PJMM] |
- unit PCoordAE;
-
- interface
-
- uses
- {$ifc not undefined THINK_PASCAL}
- InterfacesUI,
- {$endc}
- Notification, Processes, AppleTalk, PPCToolBox, EPPC, AppleEvents, { All this is necessary for Apple Events... }
- MathDeclarations, PCoord3;
-
- procedure InstallPCoordHandlers;
-
- implementation
-
- { must do this to preserve source code compatibility with CW }
- {$ifc not undefined THINK_PASCAL}
- type
- AEEventHandlerUPP = UniversalProcPtr;
- AEEventHandlerProcPtr = ProcPtr;
- function NewAEEventHandlerProc (userRoutine: AEEventHandlerProcPtr): AEEventHandlerUPP;
- inline
- $2E9F;
- {$endc}
-
- const
- kSignature = 'Rshl';
- evtInit = 'Init';
- evtAdd = 'AddO';
- evtGet = 'GetC';
- evtComp = 'comp';
-
- var
- theData, resultMatrix: TMatrixPtr;
- numRows: TInteger;
-
-
- function Initialize (var theAppleEvent: AppleEvent;
- var reply: AppleEvent;
- handlerRefCon: LongInt): OSErr;
- var
- err: OSErr;
- rows, cols: Integer;
- docList: AEDescList;
- itemsInList: LongInt;
- actualSize: Size;
- keywd: AEKeyword;
- returnedType: DescType;
- begin
- { If there is data, erase it }
- if theData <> nil then
- DisposeMatrix(theData);
- if resultMatrix <> nil then
- DisposeMatrix(resultMatrix);
-
-
- numRows := 0;
-
- { Decode the event we just received }
- err := AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, docList);
- err := AECountItems(docList, itemsInList);
- if (itemsInList = 2) and (err = noErr) then begin
- err := AEGetNthPtr(docList, 1, typeSMInt, keywd, returnedType, @rows, SizeOf(rows), actualSize);
- if err = noErr then
- err := AEGetNthPtr(docList, 2, typeSMInt, keywd, returnedType, @cols, SizeOf(cols), actualSize);
- if err = noErr then
- if not NewMatrix(theData, rows, cols, false, false) then
- err := memFullErr;
- end; { itemsInList =2 }
-
- Initialize := err;
- end; { Initialize }
-
-
- function AddObject (var theAppleEvent: AppleEvent;
- var reply: AppleEvent;
- handlerRefCon: LongInt): OSErr;
- var
- err: OSErr;
- myReal: TReal;
- docList: AEDescList;
- index, itemsInList: LongInt;
- actualSize: Size;
- keywd: AEKeyword;
- returnedType: DescType;
- begin
- { Decode the event we just received }
- err := AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, docList);
- err := AECountItems(docList, itemsInList);
- if (itemsInList > 0) and (err = noErr) then begin { fill new row of the data }
- numRows := numRows + 1;
- for index := 1 to itemsInList do begin
- if index > theData^.p then { oops! too big! }
- err := -1;
- if err = noErr then { coerce to a double }
- err := AEGetNthPtr(docList, index, typeFloat, keywd, returnedType, @myReal, SizeOf(myReal), actualSize);
- if err = noErr then begin { do something with the number }
- SetElement(theData, numRows, index, myReal);
- end; { if noErr }
- end; { for index }
- end; { itemsInList > 0 }
- AddObject := err;
- end; { AddObject }
-
- function GetOneCoordinate (var theAppleEvent: AppleEvent;
- var reply: AppleEvent;
- handlerRefCon: LongInt): OSErr;
- var
- err: OSErr;
- row, col: Integer;
- myReal: TReal;
- docList: AEDescList;
- itemsInList: LongInt;
- actualSize: Size;
- keywd: AEKeyword;
- returnedType: DescType;
- begin
- { Decode the event we just received }
- err := AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, docList);
- err := AECountItems(docList, itemsInList);
- if (itemsInList = 2) and (err = noErr) then begin
- err := AEGetNthPtr(docList, 1, typeSMInt, keywd, returnedType, @row, SizeOf(row), actualSize);
- if err = noErr then
- err := AEGetNthPtr(docList, 2, typeSMInt, keywd, returnedType, @col, SizeOf(col), actualSize);
- if err = noErr then begin { return the row/col element of result matrix in the reply appleevent }
- myReal := -1;
- if ((row > 0) and (row <= resultMatrix^.n)) and ((col > 0) and (col <= resultMatrix^.p)) then
- myReal := GetElement(resultMatrix, row, col);
- err := AEPutParamPtr(reply, keyDirectObject, typeFloat, @myReal, SizeOf(myReal));
- end;
- end; { itemsInList =2 }
- GetOneCoordinate := err;
- end; { GetOneCoordinate }
-
-
- { Compute the euclidean distance between all objects of source }
- procedure EuclideanDistance (source: TMatrixPtr;
- var result: TMatrixPtr);
- var
- i, j, nbObjets: TInteger;
- val: TReal;
-
- function D01 (LIGNE1, LIGNE2: TInteger): TReal;
- var
- COLONNE: INTEGER;
- X, Y, XX: TReal;
- begin
- XX := 0;
- for COLONNE := 1 to source^.p do begin
- X := GetElement(source, Ligne1, COLONNE);
- Y := GetElement(source, Ligne2, COLONNE);
- XX := XX + SQR(X - Y);
- end;
- D01 := SQRT(XX);
- end; (* FIN D01 *)
-
- begin
- result := nil;
- nbObjets := source^.n;
- if NewMatrix(result, nbObjets, nbObjets, false, false) then begin { square matrix }
- for i := 1 to nbObjets do begin
- for j := i + 1 to nbObjets do begin
- val := D01(i, j);
- SetElement(result, i, j, val);
- SetElement(result, j, i, val); { set lower triangular, for symmetry }
- end;
- SetElement(result, i, i, 0); { set diagonal to zero for completion's sake }
- end;
- end;
- end; { EuclideanDistance }
-
- procedure CentrerEtReduire (var m: TMatrixPtr;
- c: TInteger);
- var
- moyenne, ecartType, somme, sommeCarres, val: TReal;
- i: TInteger;
- begin
- Assert(m <> nil);
- if (c > 0) and (c <= m^.p) then begin
- somme := 0;
- sommeCarres := 0;
- for i := 1 to m^.n do begin
- val := GetElement(m, i, c);
- somme := somme + val;
- sommeCarres := sommeCarres + (val * val);
- end; { for i }
-
- moyenne := somme / m^.n;
- ecartType := Sqrt((sommeCarres - (somme * somme) / m^.n) / (m^.n - 1));
- if ecartType = 0 then
- ecartType := 1;
-
- for i := 1 to m^.n do begin
- val := GetElement(m, i, c);
- val := (val - moyenne) / ecartType;
- SetElement(m, i, c, val);
- end; { for i }
- end;
- end; { CentrerEtReduire }
-
- function Compute (var theAppleEvent: AppleEvent;
- var reply: AppleEvent;
- handlerRefCon: LongInt): OSErr;
- var
- euclideanMatrix: TMatrixPtr;
- docList: AEDescList;
- itemsInList: LongInt;
- keywd: AEKeyword;
- err: OSErr;
- i, numDim, width, height: Integer;
- actualSize: Size;
- returnedType: DescType;
- x, y, xmin, xmax, ymin, ymax, xScale, yScale: TReal;
- begin
- err := noErr;
- euclideanMatrix := nil;
-
- { Decode the event we just received }
- err := AEGetParamPtr(theAppleEvent, keyDirectObject, typeSMInt, returnedType, @numDim, SizeOf(numDim), actualSize);
- err := AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, docList);
- err := AECountItems(docList, itemsInList);
- if (itemsInList = 3) and (err = noErr) then begin
- err := AEGetNthPtr(docList, 1, typeSMInt, keywd, returnedType, @numDim, SizeOf(numDim), actualSize);
- if err = noErr then
- err := AEGetNthPtr(docList, 2, typeSMInt, keywd, returnedType, @width, SizeOf(width), actualSize);
- if err = noErr then
- err := AEGetNthPtr(docList, 3, typeSMInt, keywd, returnedType, @height, SizeOf(height), actualSize);
- end; { itemsInList =2 }
-
- { Standardize the columns so they are dimensionally homogeneous }
-
- for i := 1 to theData^.p do
- CentrerEtReduire(theData, i);
-
- EuclideanDistance(theData, euclideanMatrix);
-
- if (numDim <= theData^.p) and (err = noErr) then
- resultMatrix := GetCoords(euclideanMatrix, true, numDim); { distance matrix, numDim dimensions }
- if resultMatrix = nil then
- err := memFullErr;
-
- if (err = noErr) and (width > 0) and (height > 0) then begin { scale the coordinates in the width/height }
- { find mins and maxs }
- xmin := 10E60; { some large value }
- ymin := 10E60;
- xmax := -10E60;
- ymax := -10E60;
- for i := 1 to resultMatrix^.n do begin
- x := GetElement(resultMatrix, i, 1);
- y := GetElement(resultMatrix, i, 2);
- if xmin > x then
- xmin := x;
- if ymin > y then
- ymin := y;
- if xmax < x then
- xmax := x;
- if ymax < y then
- ymax := y;
- end; { for i }
-
- { scale factors }
- xScale := abs(xmax - xmin) / width;
- yScale := abs(ymax - ymin) / height;
-
- { actual scaling }
- for i := 1 to resultMatrix^.n do begin
- x := GetElement(resultMatrix, i, 1);
- y := GetElement(resultMatrix, i, 2);
- SetElement(resultMatrix, i, 1, x / xScale);
- SetElement(resultMatrix, i, 2, y / yScale);
- end; { for i }
-
- end; { scaling }
-
- DisposeMatrix(euclideanMatrix);
-
- Compute := err;
-
- { We now have a valid resultMatrix }
- end; { Compute }
-
-
- procedure InstallPCoordHandlers;
- var
- err: OSErr;
- myHandlerUPP: AEEventHandlerUPP;
- begin
-
- theData := nil; { no data yet! }
- resultMatrix := nil; { same }
- numRows := 0;
-
- myHandlerUPP := NewAEEventHandlerProc(@Initialize);
- err := AEInstallEventHandler(kSignature, evtInit, myHandlerUPP, 0, False);
-
- myHandlerUPP := NewAEEventHandlerProc(@AddObject);
- err := AEInstallEventHandler(kSignature, evtAdd, myHandlerUPP, 0, False);
-
- myHandlerUPP := NewAEEventHandlerProc(@GetOneCoordinate);
- err := AEInstallEventHandler(kSignature, evtGet, myHandlerUPP, 0, False);
-
- myHandlerUPP := NewAEEventHandlerProc(@Compute);
- err := AEInstallEventHandler(kSignature, evtComp, myHandlerUPP, 0, False);
-
- end;
-
-
- end.{ unit }